const EXTENT = 8192;

export class Util {
  public static getWebGLContext(canvas: HTMLCanvasElement, width: number, height: number): WebGLRenderingContext | null {
    // Resize the size of canvas
    const pixelRatio = window.devicePixelRatio || 1;
    canvas.width = pixelRatio * width;
    canvas.height = pixelRatio * height;
    canvas.style.width = `${width}px`;
    canvas.style.height = `${height}px`;

    const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");

    if (gl) {
      return gl;
    }
    return null;
  }

  /**
   * constrain n to the given range, excluding the minimum, via modular arithmetic
   *
   * @param n value
   * @param min the minimum value to be returned, exclusive
   * @param max the maximum value to be returned, inclusive
   * @returns constrained number
   * @private
   */
  public static wrap(n: number, min: number, max: number): number {
    const d = max - min;
    const w = ((n - min) % d + d) % d + min;
    return (w === min) ? max : w;
  }

  /**
   * constrain n to the given range via min + max
   *
   * @param n value
   * @param min the minimum value to be returned
   * @param max the maximum value to be returned
   * @returns the clamped value
   * @private
   */
  static clamp(n: number, min: number, max: number): number {
    return Math.min(max, Math.max(min, n));
  }

  /**
   * Converts a pixel value at a the given zoom level to tile units.
   *
   * The shaders mostly calculate everything in tile units so style
   * properties need to be converted from pixels to tile units using this.
   *
   * For example, a translation by 30 pixels at zoom 6.5 will be a
   * translation by pixelsToTileUnits(30, 6.5) tile units.
   *
   * @returns value in tile units
   */
  static pixelsToTileUnits(tile: {coord: {z:number}, tileSize: number}, pixelValue: number, z: number): number {
    return pixelValue * (EXTENT / (tile.tileSize * Math.pow(2, z - tile.coord.z)));
  }
}